package game.engine;

import game.sprite.Background;
import game.sprite.PlayerSprite;
import game.sprite.Sprite;
import game.sprite.collision.ICollidable;
import game.sprite.collision.ICollisionManager;
import game.sprite.collision.SimpleCollisionManager;

import game.userinteraction.UserInputHandler;
import java.awt.Graphics2D;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import javax.swing.Action;


/**
 * This is an abstract class representing a GameLevel for a 2d shooting game.
 * The level must be able to paint
 * all of its components and check for collisions. It must have accesors for the
 *  GameController to read its state.
 * 
 * @author team2
 * 
 */
public abstract class GameLevel {

    private List<Sprite> myLevelSprites;
    private boolean myIsRunning;
    private List<GameRule> myGameRules;
    private Map<String, Action> myActionMap;
    private Sprite myPlayer;
    private Background myBackground;
    private UserInputHandler myInputHandler;
    private ICollisionManager myCollisionManager = new SimpleCollisionManager();

    /**
     * Constructor.
     * @param levelInfo Level info file.
     * @param levelRules List of level rules.
     * @param inputHandler Input handler to use.
     */
    public GameLevel (File levelInfo, List<GameRule> levelRules,  UserInputHandler inputHandler) {
        // myLevelSprites = LevelCreator.createLevel(levelInfo);
        myGameRules = levelRules;
        myInputHandler = inputHandler;
    }

    /**
     * Update all the sprites in the current level
     * 
     * @return Returns a constant representing whether the level is still
     *         running - needs a new level etc.
     *         The possible constants to return should be specified via
     *         reflection.
     * @param userActions       Queue of user actions.
     * @param pen               Graphics to draw with.
     */
    public int updateAndPaint (Graphics2D pen, Queue<String> userActions) {
        processUserActions(userActions);
        update();
        paint(pen);
        return 0;
    }

    @SuppressWarnings("unused")
    private void processUserActions (Queue<String> userActions) {
        while (userActions != null && !userActions.isEmpty()) {
            Action playerAction = myActionMap.get(userActions.remove());
            // playerAction.actionPerformed(arg0)
        }

    }

    /**
     * Paint all the sprites in the level
     */
    private void paint (Graphics2D pen) {
        //System.out.println("painting");
        myBackground.paint(pen);
        for (Sprite s: myLevelSprites) {
            s.draw(pen);
        }
    }

    /**
     * 
     * @return the state of the game after updating the sprites
     */
    private void update () {
        myInputHandler.update();
        checkCollisions();

        for(Sprite s: myLevelSprites){
            s.update();
        }
        checkLevelRules();
        myBackground.update(myPlayer);

    }

    private void checkLevelRules () {
        for (GameRule levelRule: myGameRules) {
            levelRule.checkRules();
        } 

    }

    /**
     * 
     * @return Returns true if running.
     */
    public boolean isRunning() {
        return myIsRunning;
    }

    /**
     * Check all the collisions using the documentation in the method..
     */
    private void checkCollisions () {
        myCollisionManager.update();
    }

    /**
     * 
     * @return The map of strings to actions.
     */
    public Map<String, Action> getActionMap () {
        return myActionMap;
    }

    /**
     * 
     * @param newBackground The background.
     */
    public void setBackground(Background newBackground) {
        myBackground = newBackground;
    }

    /**
     * 
     * @param newPlayer PlayerSprite to set as the player.
     */
    public void setPlayer(PlayerSprite newPlayer) {
        myPlayer = newPlayer;
    }

    /**
     * 
     * @param levelSprites List of levels.
     */
    public void setLevelSprites(List<Sprite> levelSprites) {
        myLevelSprites = levelSprites;
    }
    /**
     * 
     * @param levelRules List of rules.
     */
    public void setLevelRules(List<GameRule> levelRules) {
        myGameRules = levelRules;
    }
    /**
     * 
     * @return The player sprite.
     */
    public PlayerSprite getPlayer() {
        return (PlayerSprite) myPlayer;
    }
    /**
     * 
     * @param toAdd Sprite to add to the game.
     */
    public void addSprite(Sprite toAdd) {
        myLevelSprites.add(toAdd);
    }
    /**
     * 
     * @param collider Add an ICollidable to the game.
     */
    public void addCollidable(ICollidable collider) {
        myCollisionManager.add(collider);
    }
    /**
     * 
     * @param collider Remove an ICollidable
     */
    public void removeCollidable(ICollidable collider) {
        myCollisionManager.remove(collider);
    }

    public List<Sprite> getLevelSprites(){
        return myLevelSprites;
    }


}
